
#pragma once

#include "MathCommon.h"
#include "Vec2.h"


class vec3
{
public:
    union
    {
        struct
        {
            float x, y, z;
        };
        struct
        {
            float r, g, b;
        };
    };
    
    vec3():								x(0), y(0), z(0)			 {}
    vec3(float xv, float yv, float zv): x(xv), y(yv), z(zv)			 {}
    vec3(const vec3& vec):				x(vec.x), y(vec.y), z(vec.z) {}
	vec3(const vec2& vec):				x(vec.x), y(vec.y), z(0.0)	 {}
    ~vec3() {}
    
    float length();
	vec3& normalize();
    
    vec3& operator = (const vec3& vec);
    vec3& operator - ();
    
    friend bool		   operator == (const vec3& left, const vec3& right);
    friend vec3&	   operator += (vec3& left, const vec3& right);
    friend vec3&	   operator -= (vec3& left, const vec3& right);
	friend vec3&	   operator *= (vec3& left, const float right);
    friend const vec3  operator +  (const vec3& left, const vec3& right);
    friend const vec3  operator -  (const vec3& left, const vec3& right);
    friend const vec3  operator *  (const vec3& vec, const float right);
    friend const float operator *  (const vec3& left, const vec3& val);
	friend const vec3  operator ^  (const vec3& left, const vec3& right);
};



inline float vec3::length()
{
    return sqrt(x * x + y * y + z * z);
}

inline vec3& vec3::normalize()
{
	float invLen = 1.0f / sqrt(x * x + y * y + z * z);

	x *= invLen;
	y *= invLen;
	z *= invLen;

	return *this;
}

inline vec3& vec3::operator = (const vec3& vec)
{
    x = vec.x;
    y = vec.y;
	z = vec.z;

    return *this;
}

inline vec3& vec3::operator - ()
{
    x *= -1;
    y *= -1;
	z *= -1;

    return *this;
}

inline bool operator == (const vec3& left, const vec3& right)
{
    return (left.x == right.x) && 
		   (left.y == right.y) &&
		   (left.z == right.z);
}

inline vec3& operator += (vec3& left, const vec3& right)
{
    left.x += right.x;
    left.y += right.y;
	left.z += right.z;

    return left;
}

inline vec3& operator -= (vec3& left, const vec3& right)
{
    left.x -= right.x;
    left.y -= right.y;
	left.z -= right.z;

    return left;
}

inline vec3& operator *= (vec3& left, const float right)
{
	left.x *= right;
    left.y *= right;
	left.z *= right;

    return left;
}

inline const vec3 operator + (const vec3& left, const vec3& right)
{
    vec3 res(left.x + right.x, left.y + right.y, left.z + right.z);

    return res;
}

inline const vec3 operator - (const vec3& left, const vec3& right)
{
    vec3 res(left.x - right.x, left.y - right.y, left.z - right.z);

    return res;
}

inline const float operator * (const vec3& left, const vec3& right)
{
    return left.x * right.x + left.y * right.y + left.z * right.z;
}

inline const vec3 operator * (const vec3& vec, const float val)
{
    vec3 res(vec.x * val, vec.y * val, vec.z * val);

    return res;
}

inline const vec3  operator ^  (const vec3& left, const vec3& right)
{
	vec3 v(left.y * right.z - left.z * right.y,
		   left.z * right.x - left.x * right.z,
		   left.x * right.y - left.y * right.x);

    return v;
}